package com.lbh.structures.common;

import com.alibaba.fastjson.annotation.JSONField;
import com.jogamp.opengl.GL2;
import com.lbh.structures.components.Component;
import com.lbh.structures.math.Quaternion;
import com.lbh.structures.math.Vector3;
import com.lbh.structures.components.render.Mesh;

import java.util.ArrayList;
import java.util.List;

/***
 * project:JRuntime
 * package:com.lbh.structures
 *
 * @author user:lenovo QQ:1601078366
 * @date 2021/10/18 0:03
 * @version V1.0
 */
public class GameObject {

    @JSONField(name = "name")
    public String name = "GameObject";
    @JSONField(name = "transform")
    public Transform transform;
    @JSONField(ordinal = 2, name = "children")
    public List<GameObject> children;
    @JSONField(ordinal = 1, name = "components")
    public List<Component> components;

    public static GameObject createPrimitive(int type){
        GameObject go = new GameObject();
        go.transform = new Transform();
        go.transform.position = Vector3.zero.clone();
        go.transform.rotation = Quaternion.none.clone();
        go.transform.scale = new Vector3(1.0F, 1.0F, 1.0F);
        go.children = new ArrayList<>();
        go.components = new ArrayList<>();
        go.addComponent(Mesh.createPrimitive(type));
        return go;
    }

    public void start(){
        for (Component component : components) {
            component.start();
        }
        for (GameObject child : children) {
            child.start();
        }
    }

    public void update(){
        for (Component component : components) {
            component.update();
        }
        for (GameObject child : children) {
            child.update();
        }
    }

    public void render(GL2 gl){
        gl.glPushMatrix();
        gl.glTranslatef(transform.position.x, transform.position.y, transform.position.z);
        gl.glRotatef(2.0F * 57.29577951308F * (float)Math.acos(transform.rotation.w),
                transform.rotation.x, transform.rotation.y, transform.rotation.z);
        gl.glScalef(transform.scale.x, transform.scale.y, transform.scale.z);
        for (Component component : components) {
            component.render(gl);
        }
        for (GameObject child : children) {
            if (child != null){
                child.render(gl);
            }
        }
        gl.glPopMatrix();
    }

    public <T extends Component> T addComponent(Class<T> type){
        T component;
        try {
            component = type.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            return null;
        }
        component.gameObject = this;
        components.add(component);
        return component;
    }

    public void addComponent(Component component){
        if (component == null) {
            return;
        }
        component.gameObject = this;
        components.add(component);
    }

    public <T extends Component> T getComponent(Class<T> type){
        for (Component component : components) {
            if (component.getClass() == type){
                return (T) component;
            }
        }
        return null;
    }

    public <T extends Component> T removeComponent(Class<T> type){
        for (Component component : components) {
            if (component.getClass() == type){
                components.remove(component);
                return (T) component;
            }
        }
        return null;
    }
}
